// --------------------------------------------------------------------------------------------------------------------- 
// <copyright file="EventProcessorsLoader.cs" company="Scrum for Team System">
//   None
// </copyright>
// <summary>
//   Defines the EventProcessorsLoader type.
// </summary>
// ---------------------------------------------------------------------------------------------------------------------

namespace ScrumForTeamSystem.EventService.Services
{
    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel.Composition;
    using System.ComponentModel.Composition.Hosting;
    using System.Reflection;
    using System.Text;

    using ScrumForTeamSystem.EventService.Infrastructure;
    using ScrumForTeamSystem.EventService.Infrastructure.Interfaces;
    using ScrumForTeamSystem.EventService.Services.Properties;

    /// <summary>
    /// Defines the EventProcessorsLoader type.
    /// </summary>
    internal class EventProcessorsLoader
    {
        /// <summary>
        /// The name of the service
        /// </summary>
        private const string ServiceName = "EventProcessorsLoader";

        /// <summary>
        /// Instance of the Message logging service
        /// </summary>
        private readonly IActionLoggingService actionLoggingService;

        /// <summary>
        /// Instance of the worker process
        /// </summary>
        private readonly IWorkerProcess workerProcess;

        /// <summary>
        /// The event processors collection.
        /// </summary>
        [ImportMany] 
        private readonly Collection<ITfsEventProcessor> eventProcessors = new Collection<ITfsEventProcessor>();

        /// <summary>
        /// Initializes a new instance of the <see cref="EventProcessorsLoader"/> class.
        /// </summary>
        /// <param name="workerProcess">The worker process.</param>
        /// <param name="actionLoggingService">The action logging service.</param>
        public EventProcessorsLoader(IWorkerProcess workerProcess, IActionLoggingService actionLoggingService)
        {
            this.workerProcess = workerProcess;
            this.actionLoggingService = actionLoggingService;
        }

        /// <summary>
        /// Gets a value indicating whether this instance Has a Valid Action Log Service.
        /// </summary>
        /// <value>The has valid action log service.</value>
        private bool HasValidActionLogService
        {
            get
            {
                return this.actionLoggingService != null;
            }
        }

        /// <summary>
        /// Loads the plugin assemblies.
        /// </summary>
        /// <exception cref="Exception">
        /// </exception>
        public void LoadPluginAssemblies()
        {
            this.Compose();
            this.Validate();
            this.RegisterProcessors();
        }

        /// <summary>
        /// Validates this instance.
        /// </summary>
        /// <exception cref="ServiceException" />
        private void Validate()
        {
            if (this.eventProcessors.Count == 0)
            {
                this.actionLoggingService.WriteToEventLog(new ServiceException(ServiceName, "No event processor exports found."));
            }
        }

        /// <summary>
        /// Registers the processors.
        /// </summary>
        private void RegisterProcessors()
        {
            var message = string.Empty;

            foreach (var processor in this.eventProcessors)
            {
                var type = processor.GetType();
                if (this.HasValidActionLogService && typeof(IMessageProducer).IsAssignableFrom(type))
                {
                    this.actionLoggingService.RegisterLogGenerator((IMessageProducer)processor);
                    message = string.Concat(message, string.IsNullOrEmpty(message) ? string.Empty : "\r\n", type);
                }

                this.workerProcess.RegisterEventProcessor(processor);
            }

            if (!string.IsNullOrEmpty(message))
            {
                this.actionLoggingService.WriteToEventLog(
                        string.Concat(Resources.String009, Environment.NewLine, message));
            }
        }

        /// <summary>
        /// Composes this instance.
        /// </summary>
        private void Compose()
        {
            try
            {
                using (var catalog = new DirectoryCatalog(Settings.Default.PluginDirectory))
                using (var container = new CompositionContainer(catalog))
                {
                    var batch = new CompositionBatch();
                    batch.AddPart(this);
                    container.Compose(batch);
                }
            }
            catch (ReflectionTypeLoadException loaderEx)
            {
                var loaderExceptions = new StringBuilder();
                loaderExceptions.AppendLine(Resources.String010);

                foreach (var loaderException in loaderEx.LoaderExceptions)
                {
                    loaderExceptions.AppendLine(loaderException.Message);
                }

                throw new ServiceException(ServiceName, loaderExceptions.ToString(), loaderEx);
            }
        }
    }
}